'---------------------------------------------------------------------
'THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
'KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
'IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
'PARTICULAR PURPOSE.
'---------------------------------------------------------------------
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Design
Imports System.Globalization
Imports System.Security.Permissions

Namespace Microsoft.Samples.Alert

    ''' <summary>
    ''' The alert class makes it easy to display rich client-side message boxes using server code.
    ''' </summary>
    <ToolboxData("<{0}:Alert runat=\""server\""></{0}:Alert>"), _
     ParseChildren(False), _
     PersistChildren(True)> _
    Public Class Alert
        Inherits WebControl
        Implements IPostBackEventHandler

        Private Shared EventChoice As Object = New Object

        ' The two parts of the script that will display the Alert.
        ' The middle part will be the url of the DisplayAlert.htm page that will
        ' render the modal dialog from the parameters it's being passed.
        ' The script degrades to an alert or a confirm on non-IE browsers.
        ' The getInnerText extracts the text from the HTML of the Alert in order to
        ' display it on browsers that can't show modal dialogs.
        Private _script1 As String = vbCrLf & _
            "function messageBoxShow(msgBoxID, buttons) {" & vbCrLf & _
            vbTab & "var msgBox = (document.all ? document.all[msgBoxID] : document.getElementById(msgBoxID));" & vbCrLf & _
            vbTab & "if (window.showModalDialog) {" & vbCrLf & _
            vbTab & vbTab & "var parameters = new Array(2);" & vbCrLf & _
            vbTab & vbTab & "parameters[0] = msgBox.title;" & vbCrLf & _
            vbTab & vbTab & "parameters[1] = msgBox.outerHTML;" & vbCrLf & _
            vbTab & vbTab & "return window.showModalDialog('"

        Private _script2 As String = "', parameters, 'resizable:yes;scroll:no;status:no;help:no;dialogHeight:' + msgBox.style.height + ';dialogWidth:' + msgBox.style.width + ';center:yes');" & vbCrLf & _
            vbTab & "}" & vbCrLf & _
            vbTab & "else {" & vbCrLf & _
            vbTab & vbTab & "var txt = getInnerText(msgBox);" & vbCrLf & _
            vbTab & vbTab & "if (buttons) {" & vbCrLf & _
            vbTab & vbTab & vbTab & "return confirm(txt);" & vbCrLf & _
            vbTab & vbTab & "}" & vbCrLf & _
            vbTab & vbTab & "else {" & vbCrLf & _
            vbTab & vbTab & vbTab & "alert(txt);" & vbCrLf & _
            vbTab & vbTab & vbTab & "return true;" & vbCrLf & _
            vbTab & vbTab & "}" & vbCrLf & _
            vbTab & "}" & vbCrLf & _
            "}" & vbCrLf & _
            "function getInnerText(element) {" & vbCrLf & _
            vbTab & "var innerText = """";" & vbCrLf & _
            vbTab & "if (element.nodeType == 3 && element.nodeValue) {" & vbCrLf & _
            vbTab & vbTab & "innerText = element.nodeValue;" & vbCrLf & _
            vbTab & "}" & vbCrLf & _
            vbTab & "var children = element.childNodes;" & vbCrLf & _
            vbTab & "if (children.length > 0) {" & vbCrLf & _
            vbTab & vbTab & "for(var i = 0; i < children.length; i++) {" & vbCrLf & _
            vbTab & vbTab & vbTab & "innerText += getInnerText(children[i]);" & vbCrLf & _
            vbTab & vbTab & "}" & vbCrLf & _
            vbTab & "}" & vbCrLf & _
            vbTab & "return innerText;" & vbCrLf & _
            "}" & vbCrLf

        Public Sub New()
            MyBase.New(HtmlTextWriterTag.Div)
        End Sub

        ''' <summary>
        ''' The text of the Abort button.
        ''' </summary>
        <Category("ButtonText"), _
         DefaultValue("Abort"), _
         Description("The text of the Abort button.")> _
        Public Overridable Property AbortText() As String
            Get
                Dim s As String = CType(ViewState("AbortText"), String)
                If (s Is Nothing) Then
                    Return "Abort"
                Else
                    Return s
                End If
            End Get
            Set(ByVal value As String)
                ViewState("AbortText") = Value
            End Set
        End Property

        ''' <summary>
        ''' The url of the background image.
        ''' </summary>
        <Category("Appearance"), _
         DefaultValue(""), _
         Description("The url of the background image."), _
         UrlProperty()> _
        Public Overridable Property BackImageUrl() As String
            Get
                Dim s As String = CType(ViewState("BackImageUrl"), String)
                If (s Is Nothing) Then
                    Return [String].Empty
                Else
                    Return s
                End If
            End Get
            Set(ByVal value As String)
                ViewState("BackImageUrl") = Value
            End Set
        End Property

        ''' <summary>
        ''' The number and nature of the buttons to use for the alert.
        ''' </summary>
        <Category("Appearance"), _
         DefaultValue(AlertButtons.OK), _
         Description("The number and nature of the buttons to use for the alert.")> _
        Public Overridable Property Buttons() As AlertButtons
            Get
                Dim b As Object = ViewState("Buttons")
                If (b Is Nothing) Then
                    Return AlertButtons.OK
                Else
                    Return CType(b, AlertButtons)
                End If
            End Get
            Set(ByVal value As AlertButtons)
                If ((value < AlertButtons.AbortRetryIgnore) OrElse (value > AlertButtons.YesNoCancel)) Then
                    Throw New ArgumentOutOfRangeException("value")
                End If
                ViewState("Buttons") = value
            End Set
        End Property

        ''' <summary>
        ''' The text of the Cancel button.
        ''' </summary>
        <Category("ButtonText"), _
         DefaultValue("Cancel"), _
         Description("The text of the Cancel button.")> _
        Public Overridable Property CancelText() As String
            Get
                Dim s As String = CType(ViewState("CancelText"), String)
                If (s Is Nothing) Then
                    Return "Cancel"
                Else
                    Return s
                End If
            End Get
            Set(ByVal value As String)
                ViewState("CancelText") = Value
            End Set
        End Property

        ''' <summary>
        ''' The direction of the text in the Alert box.
        ''' </summary>
        <Category("Layout"), _
         DefaultValue(ContentDirection.NotSet), _
         Description("The direction of the text in the Alert box.")> _
        Public Overridable Property Direction() As ContentDirection
            Get
                Dim o As Object = ViewState("Direction")
                If (o Is Nothing) Then
                    Return ContentDirection.NotSet
                Else
                    Return CType(o, ContentDirection)
                End If
            End Get
            Set(ByVal value As ContentDirection)
                If ((value < ContentDirection.NotSet) OrElse (value > ContentDirection.RightToLeft)) Then
                    Throw New ArgumentOutOfRangeException("value")
                End If
                ViewState("Direction") = value
            End Set
        End Property

        ''' <summary>
        ''' The horizontal alignement of the contents of the Alert.
        ''' </summary>
        <Category("Layout"), _
         DefaultValue(HorizontalAlign.NotSet), _
         Description("The horizontal alignement of the contents of the Alert.")> _
        Public Overridable Property HorizontalAlign() As HorizontalAlign
            Get
                Dim o As Object = ViewState("HorizontalAlign")
                If (o Is Nothing) Then
                    Return HorizontalAlign.NotSet
                Else
                    Return CType(o, HorizontalAlign)
                End If
            End Get
            Set(ByVal value As HorizontalAlign)
                If ((Value < HorizontalAlign.NotSet) OrElse (Value > HorizontalAlign.Justify)) Then
                    Throw New ArgumentOutOfRangeException("value")
                End If
                ViewState("HorizontalAlign") = Value
            End Set
        End Property

        ''' <summary>
        ''' The text of the Ignore button.
        ''' </summary>
        <Category("ButtonText"), _
         DefaultValue("Ignore"), _
         Description("The text of the Ignore button.")> _
        Public Overridable Property IgnoreText() As String
            Get
                Dim s As String = CType(ViewState("IgnoreText"), String)
                If (s Is Nothing) Then
                    Return "Ignore"
                Else
                    Return s
                End If
            End Get
            Set(ByVal value As String)
                ViewState("IgnoreText") = Value
            End Set
        End Property

        ''' <summary>
        ''' The text of the No button.
        ''' </summary>
        <Category("ButtonText"), _
         DefaultValue("No"), _
         Description("The text of the No button.")> _
        Public Overridable Property NoText() As String
            Get
                Dim s As String = CType(ViewState("NoText"), String)
                If (s Is Nothing) Then
                    Return "No"
                Else
                    Return s
                End If
            End Get
            Set(ByVal value As String)
                ViewState("NoText") = Value
            End Set
        End Property

        ''' <summary>
        ''' The text of the OK button.
        ''' </summary>
        <Category("ButtonText"), _
         DefaultValue("OK"), _
         Description("The text of the OK button.")> _
        Public Overridable Property OKText() As String
            Get
                Dim s As String = CType(ViewState("OKText"), String)
                If (s Is Nothing) Then
                    Return "OK"
                Else
                    Return s
                End If
            End Get
            Set(ByVal value As String)
                ViewState("OKText") = Value
            End Set
        End Property

        ''' <summary>
        ''' The text of the Retry button.
        ''' </summary>
        <Category("ButtonText"), _
         DefaultValue("Retry"), _
         Description("The text of the Retry button.")> _
        Public Overridable Property RetryText() As String
            Get
                Dim s As String = CType(ViewState("RetryText"), String)
                If (s Is Nothing) Then
                    Return "Retry"
                Else
                    Return s
                End If
            End Get
            Set(ByVal value As String)
                ViewState("RetryText") = Value
            End Set
        End Property

        ''' <summary>
        ''' Determines what scroll bars can appear on the Alert.
        ''' </summary>
        <Category("Layout"), _
         DefaultValue(ScrollBars.None), _
         Description("Determines what scroll bars can appear on the Alert.")> _
        Public Overridable Property ScrollBars() As ScrollBars
            Get
                Dim scroll As Object = ViewState("ScrollBars")
                If (scroll Is Nothing) Then
                    Return ScrollBars.None
                Else
                    Return CType(scroll, ScrollBars)
                End If
            End Get
            Set(ByVal value As ScrollBars)
                If ((value < ScrollBars.None) OrElse (value > ScrollBars.Auto)) Then
                    Throw New ArgumentOutOfRangeException("value")
                End If
                ViewState("ScrollBars") = value
            End Set
        End Property

        ''' <summary>
        ''' The title of the alert.
        ''' </summary>
        <Category("Layout"), _
         DefaultValue(""), _
         Description("The title of the alert.")> _
        Public Overridable Property Title() As String
            Get
                Dim s As String = CType(ViewState("Title"), String)
                If (s Is Nothing) Then
                    Return String.Empty
                Else
                    Return s
                End If
            End Get
            Set(ByVal value As String)
                ViewState("Title") = Value
            End Set
        End Property

        ''' <summary>
        ''' Set to false if the text in the Alert should not be allowed to wrap.
        ''' </summary>
        <Category("Layout"), _
         DefaultValue(True), _
         Description("Set to false if the text in the Alert should not be allowed to wrap.")> _
        Public Overridable Property Wrap() As Boolean
            Get
                Dim b As Object = ViewState("Wrap")
                If (b Is Nothing) Then
                    Return True
                Else
                    Return CType(b, Boolean)
                End If
            End Get
            Set(ByVal value As Boolean)
                ViewState("Wrap") = Value
            End Set
        End Property

        ''' <summary>
        ''' The text of the Yes button.
        ''' </summary>
        <Category("ButtonText"), _
         DefaultValue("Yes"), _
         Description("The text of the Yes button.")> _
        Public Overridable Property YesText() As String
            Get
                Dim s As String = CType(ViewState("YesText"), String)
                If (s Is Nothing) Then
                    Return "Yes"
                Else
                    Return s
                End If
            End Get
            Set(ByVal value As String)
                ViewState("YesText") = Value
            End Set
        End Property

        ''' <summary>
        ''' The event that is raised when an option is clicked in the Alert.
        ''' </summary>
        Public Event Choice As AlertChoiceEventHandler

        Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)
            MyBase.AddAttributesToRender(writer)
            Dim s As String = BackImageUrl
            If (s.Trim.Length > 0) Then
                writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, ("url(" _
                                + (ResolveClientUrl(s) + ")")))
            End If

            Select Case ScrollBars
                Case WebControls.ScrollBars.Horizontal
                    writer.AddStyleAttribute(HtmlTextWriterStyle.OverflowX, "scroll")
                Case WebControls.ScrollBars.Vertical
                    writer.AddStyleAttribute(HtmlTextWriterStyle.OverflowY, "scroll")
                Case WebControls.ScrollBars.Both
                    writer.AddStyleAttribute(HtmlTextWriterStyle.Overflow, "scroll")
                Case WebControls.ScrollBars.Auto
                    writer.AddStyleAttribute(HtmlTextWriterStyle.Overflow, "auto")
            End Select

            Dim hAlign As HorizontalAlign = HorizontalAlign
            If (hAlign <> HorizontalAlign.NotSet) Then
                Dim hac As TypeConverter = TypeDescriptor.GetConverter(GetType(HorizontalAlign))
                writer.AddAttribute(HtmlTextWriterAttribute.Align, hac.ConvertToString(hAlign).ToLower(CultureInfo.InvariantCulture))
            End If
            If (Wrap = False) Then
                writer.AddStyleAttribute(HtmlTextWriterStyle.WhiteSpace, "nowrap")
            End If
            If (Direction = ContentDirection.LeftToRight) Then
                writer.AddAttribute(HtmlTextWriterAttribute.Dir, "LTR")
            Else
                If (Direction = ContentDirection.RightToLeft) Then
                    writer.AddAttribute(HtmlTextWriterAttribute.Dir, "RTL")
                End If
            End If
            ' Position
            writer.AddStyleAttribute("display", "none")
            ' Title
            writer.AddAttribute("title", Title, True)
        End Sub

        ''' <summary>
        ''' Get a client-side function that will show the Alert.
        ''' </summary>
        ''' <returns>The client-side code that will show the Alert</returns>
        Public Function GetShowClientEvent() As String
            Dim buttonString As String
            If (Buttons = AlertButtons.OK) Then
                buttonString = "false"
            Else
                buttonString = "true"
            End If
            Return "messageBoxShow('" & ClientID & "', " + buttonString + ")"
        End Function

        ''' <summary>
        ''' This function is called when an option is chosen in the Alert.
        ''' </summary>
        ''' <param name="e">The event arguments that contain the chosen option.</param>
        Protected Overridable Sub OnChoice(ByVal e As AlertChoiceEventArgs)
            Dim handler As AlertChoiceEventHandler = CType(Events(EventChoice), AlertChoiceEventHandler)
            If (Not (handler) Is Nothing) Then
                handler(Me, e)
            End If
        End Sub

        Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
            ' Register the Alert display script
            Page.ClientScript.RegisterClientScriptBlock(GetType(Alert), "AspNetAlert", _
                (_script1 & (Page.ResolveClientUrl("~/Alert/DisplayAlert.htm") & _script2)), True)
        End Sub

        Protected Overrides Sub RenderChildren(ByVal writer As HtmlTextWriter)
            ' First, render the contents of the Alert
            MyBase.RenderChildren(writer)
            ' Then, we prepare the button panel and its three buttons
            Dim p As Panel = New Panel
            p.ID = (UniqueID + "_Buttons")
            p.Page = Page
            Dim button1 As Button = New Button
            button1.OnClientClick = "returnValue=true;window.close();"
            p.Controls.Add(button1)
            Dim button2 As Button = New Button
            button2.OnClientClick = "returnValue=false;window.close();"
            p.Controls.Add(button2)
            Dim button3 As Button = New Button
            button3.OnClientClick = "window.close();"
            p.Controls.Add(button3)
            ' Set-up and show or hide the buttons according to the button style
            Select Case Buttons
                Case AlertButtons.AbortRetryIgnore
                    button1.Visible = True
                    button2.Visible = True
                    button3.Visible = True
                    button1.Text = AbortText
                    button2.Text = RetryText
                    button3.Text = IgnoreText
                Case AlertButtons.OK
                    button1.Visible = True
                    button2.Visible = False
                    button3.Visible = False
                    button1.Text = OKText
                Case AlertButtons.OKCancel
                    button1.Visible = True
                    button2.Visible = True
                    button3.Visible = False
                    button1.Text = OKText
                    button2.Text = CancelText
                Case AlertButtons.RetryCancel
                    button1.Visible = False
                    button2.Visible = True
                    button3.Visible = True
                    button2.Text = RetryText
                    button3.Text = CancelText
                Case AlertButtons.YesNo
                    button1.Visible = True
                    button2.Visible = True
                    button3.Visible = False
                    button1.Text = YesText
                    button2.Text = NoText
                Case AlertButtons.YesNoCancel
                    button1.Visible = True
                    button2.Visible = True
                    button3.Visible = True
                    button1.Text = YesText
                    button2.Text = NoText
                    button3.Text = CancelText
            End Select
            ' Render the button panel
            p.RenderControl(writer)
        End Sub

        ''' <summary>
        ''' Call this server-side method to ask the client to show the Alert on this request.
        ''' </summary>
        Public Sub Show()
            ' Force the page to output the postback script
            Page.ClientScript.GetPostBackEventReference(Me, [String].Empty)
            ' We can't use GetPostBackEvent here because the argument is not a string literal, but a client variable.
            Page.ClientScript.RegisterStartupScript(GetType(Alert), "ServerShowAlert", _
                "var res=" & GetShowClientEvent() & ";__doPostBack('" & UniqueID & "',res);", _
                True)
        End Sub

        Sub IPostBackEventHandler_RaisePostBackEvent(ByVal eventArgument As String) Implements IPostBackEventHandler.RaisePostBackEvent
            OnChoice(New AlertChoiceEventArgs(Buttons, eventArgument))
        End Sub
    End Class

    Public Delegate Sub AlertChoiceEventHandler(ByVal source As Object, ByVal e As AlertChoiceEventArgs)
End Namespace
